#if !defined(HTTPCONNECTION_H)
#define HTTPCONNECTION_H

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>

#include "db_connection_pool.h"
#include "locker.h"

class http_conn
{
public:
    /// @brief 文件名最大长度
    static const int FILENAME_LEN = 200;
    /// @brief 读缓冲区大小
    static const int READ_BUFFER_SIZE = 2048;
    /// @brief 写缓冲区大小
    static const int WRITE_BUFFER_SIZE = 1024;

    /// @brief HTTP请求类型
    /// @note 此处仅支持GET
    enum METHOD
    {
        GET = 0,
        POST,
        HEAD,
        PUT,
        DELETE,
        TRACE,
        OPTIONS,
        CONNECT,
        PATCH
    };

    /// @brief 解析状态
    /// @note 主状态机
    enum CHECK_STATE
    {
        CHECK_STATE_REQUESTLINE = 0,
        CHECK_STATE_HEADER,
        CHECK_STATE_CONTENT

    };
    /// @brief 服务器响应类型
    enum HTTP_CODE
    {
        NO_REQUEST,
        GET_REQUEST,
        BAD_REQUEST,
        NO_RESOURCE,
        FORBIDDEN_REQUEST,
        FILE_REQUEST,
        INTERNAL_ERROR,
        CLOSED_CONNECTION
    };

    /// @brief 行读取状态
    enum LINE_STATUS
    {
        LINE_OK = 0,
        LINE_BAD,
        LINE_OPEN
    };

public:
    /// @brief 全局内核事件表
    /// @note 所有SOCKET事件均由注册至此EPOLL内核表
    static int m_epollfd;

    /// @brief 用户量统计
    static int m_user_count;

    /// @brief 数据库连接
    sql::Connection *mysql_conn;

private:
    /// @brief 当前HTTP连接SOCKET地址
    int m_sockfd;

    /// @brief 客户端SOCKET地址
    sockaddr_in m_address;

    /// @brief 读缓冲区
    char m_read_buffer[READ_BUFFER_SIZE];

    /// @brief 读缓冲区中已经读入的客户数据的最后一个字节的下一个位置
    int m_read_idx;

    /// @brief 当前检查的字节在读缓冲区中的位置
    int m_check_idx;

    /// @brief 当前解析行起始位置
    int m_start_line;

    /// @brief 写缓冲区
    char m_write_buffer[WRITE_BUFFER_SIZE];

    /// @brief 写缓冲区中待发送的字节数
    int m_write_idx;

    /// @brief 主状态机当前状态
    CHECK_STATE m_check_state;

    /// @brief 请求方法
    METHOD m_method;

    /// @brief 客户请求的目标文件完整路径
    /// @note doc_root（网站根目录） + m_url（资源路径）
    char m_real_file[FILENAME_LEN];

    /// @brief 客户请求目标文件名
    char *m_url;

    /// @brief HTTP协议版本号
    /// @note 当前仅支持HTTP/1.1
    char *m_version;

    /// @brief 主机名
    char *m_host;

    /// @brief HTTP请求消息体长度
    int m_content_length;

    /// @brief HTTP请求是否要求长连接
    bool m_linger;

    /// @brief 客户请求被mmap到内存中的起始位置
    char *m_file_address;

    /// @brief 目标文件状态
    /// @note 可根据其分析相应文件信息
    struct stat m_file_stat;

    /* -------------- writev支持 --------------- */

    /// @brief 内存向量
    struct iovec m_iv[2];

    /// @brief 被写内存块的数量
    int m_iv_count;

    /* -------------- POST请求支持 --------------- */

    /// @brief 是否启用POST
    int cgi;
    /// @brief 请求头存储
    char *m_string;

    int bytes_to_send;
    int bytes_have_send;

public:
    http_conn() {}
    ~http_conn() {}

public:
    /* -------------- 操作函数 --------------- */

    /// @brief 初始化新接受的连接
    /// @param sockfd 客户SOCKET连接描述符
    /// @param addr 客户SOCKET连接地址
    void init(int sockfd, const sockaddr_in &addr);

    /// @brief 关闭连接
    /// @param real_close
    void close_conn(bool real_close = true);

    /// @brief 处理客户请求
    /// @note 请求处理入口函数（由线程调用）
    void process();

    /// @brief 非阻塞读操作
    /// @note 循环读取客户数据，直到无数据可读/客户关闭连接
    /// @note 非阻塞ET模式下, 需要一次性读取数据
    bool read();

    /// @brief 非阻塞写操作
    /// @note HTTP Response
    bool write();

    /// @brief
    /// @param connPool
    void initmysql_result(db_connection_pool *connPool);

    sockaddr_in *get_address()
    {
        return &m_address;
    }

private:
    /// @brief 初始化连接
    void init();

    /* ---------------- HTTP请求分析组函数 ---------------- */

    /// @brief 解析HTTP请求
    /// @return HTTP状态码
    HTTP_CODE process_read();

    /// @brief 分析请求行
    /// @note 获取请求方法、目标URL、HTTP版本号
    /// @param text
    /// @return HTTP状态码
    HTTP_CODE parse_request_line(char *text);

    /// @brief 分析请求头
    /// @param text
    /// @return HTTP状态码
    HTTP_CODE parse_headers(char *text);

    /// @brief 分析请求体
    /// @param text
    /// @return HTTP状态码
    HTTP_CODE parse_content(char *text);

    /// @brief 服务端请求处理
    /// @note 请求目标文件分析
    /// @return HTTP状态码
    HTTP_CODE do_request();

    /// @brief 获取行
    inline char *get_line() { return m_read_buffer + m_start_line; }

    /// @brief 分析行
    /// @return 行状态
    LINE_STATUS parse_line();

    /* ---------------- HTTP响应处理组函数 ---------------- */

    /// @brief 填充HTTP响应
    /// @param ret 响应状态码
    /// @return 是否成功
    bool process_write(HTTP_CODE ret);

    /// @brief 释放虚拟内存中映射的文件
    void unmap();

    /// @brief 向写缓冲添加响应
    /// @param format
    /// @param ...
    /// @return 是否成功
    bool add_response(const char *format, ...);

    /// @brief 添加响应体
    /// @param content
    /// @return 是否成功
    bool add_content(const char *content);

    /// @brief 添加响应状态行
    /// @param status
    /// @param title
    /// @return 是否成功
    bool add_status_line(int status, const char *title);

    /// @brief 添加响应头
    /// @param content_length 响应体大小
    /// @return 是否成功
    bool add_headers(int content_length);

    /// @brief 添加响应体长度
    /// @param content_length 响应体大小
    /// @return 是否成功
    bool add_content_length(int content_length);

    /// @brief 添加响应体类型
    /// @return 是否成功
    bool add_content_type();

    /// @brief 添加长连接
    /// @return 是否成功
    bool add_linger();

    /// @brief 添加空行
    /// @return 是否成功
    bool add_blank_line();
};

#endif // HTTPCONNECTION_H
